package org.example.batch;

import org.example.domain.Student;
import org.springframework.batch.item.ItemProcessor;

/**
 * 学生数据批处理器 - 教学版本
 * 
 * ItemProcessor 是 Spring Batch 中的数据处理组件，位于 Reader 和 Writer 之间
 * 
 * 主要作用：
 * 1. 数据转换：将输入类型转换为输出类型
 * 2. 数据验证：验证数据的合法性
 * 3. 数据增强：添加额外信息或计算字段
 * 4. 业务规则应用：根据业务逻辑处理数据
 * 5. 数据过滤：返回null可以过滤掉不需要的记录
 * 
 * 设计原则：
 * - 无状态：Processor应该是无状态的，不依赖外部变量
 * - 线程安全：可能被多线程调用，需要保证线程安全
 * - 异常处理：合理处理异常，决定是跳过还是失败
 * 
 * 实际应用场景：
 * - 数据格式转换（如日期格式统一）
 * - 数据清洗和标准化
 * - 业务规则验证
 * - 调用外部服务获取补充信息
 * - 数据分类和标记
 * 
 * @author example
 */
public class StudentBatchProcessor implements ItemProcessor<Student, Student> {

    /**
     * 处理单个学生记录
     * 
     * Spring Batch 会为每个从 Reader 读取的记录调用这个方法
     * 
     * @param student 从 Reader 读取的学生对象
     * @return 处理后的学生对象，如果返回null则该记录会被过滤掉
     * @throws Exception 如果处理过程中发生异常
     * 
     * 处理流程说明：
     * 1. 接收 Reader 传来的原始学生数据
     * 2. 执行业务逻辑处理
     * 3. 返回处理后的数据给 Writer
     * 
     * 异常处理策略：
     * - 如果抛出异常，该记录会被标记为处理失败
     * - 可以配置跳过策略来处理失败的记录
     * - 也可以配置重试策略来重新处理失败的记录
     */
    @Override
    public Student process(Student student) throws Exception {
        System.out.println("开始处理学生数据: ID=" + student.getId() + ", 姓名=" + student.getName());
        
        // 数据验证示例
        if (student.getName() == null || student.getName().trim().isEmpty()) {
            System.out.println("警告：学生姓名为空，跳过该记录");
            return null; // 返回null会过滤掉这条记录
        }
        
        if (student.getAge() == null) {
            System.out.println("警告：学生年龄为空，设置默认值");
            student.setAge(18); // 设置默认年龄
        }
        
        // 业务逻辑处理：根据年龄分类学生
        String ageCategory;
        if (student.getAge() < 18) {
            ageCategory = "[未成年]";
            System.out.println("  -> 分类为未成年学生");
        } else if (student.getAge() <= 25) {
            ageCategory = "[青年]";
            System.out.println("  -> 分类为青年学生");
        } else {
            ageCategory = "[成年]";
            System.out.println("  -> 分类为成年学生");
        }
        
        // 更新学生姓名，添加分类标识
        String originalName = student.getName();
        student.setName(ageCategory + originalName);
        
        // 模拟复杂的业务处理
        // 在实际应用中，这里可能包括：
        // - 调用外部API获取补充信息
        // - 数据库查询关联信息
        // - 复杂的业务规则计算
        // - 数据格式转换等
        
        // 模拟处理耗时（实际应用中删除这行）
        Thread.sleep(100);
        
        // 可以添加更多的业务处理逻辑
        // 例如：设置处理时间戳、计算衍生字段等
        
        System.out.println("处理完成: " + originalName + " -> " + student.getName() + 
                          " (年龄:" + student.getAge() + ")");
        
        // 返回处理后的学生对象
        // 注意：可以返回与输入不同类型的对象，只要泛型匹配即可
        return student;
    }
    
    // 可以添加辅助方法来支持复杂的业务逻辑
    
    /**
     * 验证学生数据的有效性
     * 这是一个辅助方法，展示如何组织复杂的处理逻辑
     */
    private boolean isValidStudent(Student student) {
        return student != null && 
               student.getName() != null && 
               !student.getName().trim().isEmpty() &&
               student.getAge() != null && 
               student.getAge() >= 0 && 
               student.getAge() <= 150;
    }
    
    /**
     * 获取年龄组
     * 辅助方法，用于根据年龄确定学生所属的年龄组
     */
    private String getAgeGroup(Integer age) {
        if (age == null) return "未知";
        if (age < 18) return "未成年";
        if (age <= 25) return "青年";
        if (age <= 60) return "中年";
        return "老年";
    }
} 